/*
 * ==========================================================================*\
 * | $Id$
 * |*-------------------------------------------------------------------------*|
 * | Copyright (C) 2009 Virginia Tech | | This file is part of CloudSpace. | |
 * CloudSpace is free software; you can redistribute it and/or modify | it under
 * the terms of the GNU General Public License as published | by the Free
 * Software Foundation; either version 3 of the License, or | (at your option)
 * any later version. | | CloudSpace is distributed in the hope that it will be
 * useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General
 * Public License for more details. | | You should have received a copy of the
 * GNU General Public License | along with CloudSpace; if not, see
 * <http://www.gnu.org/licenses/>.
 * \*==========================================================================
 */

package cloudspace.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

import org.apache.log4j.Logger;


// -------------------------------------------------------------------------
/**
 * A subclass of the java.util.Properties class that must be initialized from a
 * file on disk, and which always keeps the in-memory property set in sync with
 * the contents on disk.
 * 
 * @author Tony Allevato
 * @author Last changed by $Author$
 * @version $Revision$, $Date$
 */
public class ImmediateProperties extends Properties
{
    // ~ Constructors ..........................................................

    // ----------------------------------------------------------
    /**
     * Initializes a new instance of ImmediateProperties by loading them from
     * the specified file.
     * 
     * @param file
     *            the path to the file that backs this Properties instance.
     */
    public ImmediateProperties( File file )
    {
        super();

        this.backingFile = file;

        FileInputStream stream = null;

        try
        {
            stream = new FileInputStream( backingFile );
            load( stream );
        }
        catch ( FileNotFoundException e )
        {
            // Do nothing; start the property set empty if the file did not
            // exist.
        }
        catch ( IOException e )
        {
            log.error( "An I/O exception occurred when loading the properties "
                + "file at " + backingFile, e );
        }
        finally
        {
            try
            {
                if ( stream != null )
                {
                    stream.close();
                }
            }
            catch ( IOException e )
            {
                log.error( "An I/O exception occurred when trying to close the "
                    + "stream",
                    e );
            }
        }
    }


    // ~ Methods ...............................................................

    // ----------------------------------------------------------
    /**
     * Removes the specified property from the file.
     * 
     * @param key
     *            the name of the property to remove
     * @return the previous value of the property
     */
    @Override
    public Object remove( Object key )
    {
        Object previousValue = super.remove( key );
        writeToFile();
        return previousValue;
    }


    // ----------------------------------------------------------
    /**
     * Sets the value of the specified property.
     * 
     * @param key
     *            the name of the property to set
     * @param value
     *            the value of the property
     * @return the previous value of the property
     */
    @Override
    public Object put( Object key, Object value )
    {
        Object previousValue = super.put( key, value );
        writeToFile();
        return previousValue;
    }


    // ----------------------------------------------------------
    /**
     * Saves the current properties set to their associated file.
     */
    private void writeToFile()
    {
        FileOutputStream stream = null;

        try
        {
            stream = new FileOutputStream( backingFile );
            store( stream, null );
        }
        catch ( IOException e )
        {
            log.error( "An I/O exception occurred when saving the properties",
                e );
        }
        finally
        {
            try
            {
                if ( stream != null )
                {
                    stream.close();
                }
            }
            catch ( IOException e )
            {
                log.error( "An I/O exception occurred when closing the stream",
                    e );
            }
        }
    }

    // ~ Instance/static variables .............................................

    /** The path to the file that backs this Properties instance. */
    private File backingFile;

    private static final long serialVersionUID = -6139105936918525923L;

    private static final Logger log = Logger.getLogger( ImmediateProperties.class );
}
